package com.springboot.service.blog;

import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.auth0.jwt.JWT;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.springboot.config.error.MySpringBootException;
import com.springboot.dao.BlogCommentDao;
import com.springboot.dao.BlogRegisterTimeDao;
import com.springboot.dao.BlogUserDao;
import com.springboot.dao.BlogUserLoginJwtDao;
import com.springboot.entity.BlogCommentEntity;
import com.springboot.entity.BlogRegisterTimeEntity;
import com.springboot.entity.BlogUserEntity;
import com.springboot.entity.BlogUserLoginJwtEntity;
import com.springboot.jwt.config.JwtUtil;
import com.springboot.jwt.dto.JWTHeaderDto;
import com.springboot.jwt.dto.JWTPayload;
import com.springboot.returndata.dto.blog.BlogCommentDto;
import com.springboot.returndata.dto.blog.BlogUserPageDto;
import com.springboot.returndata.dto.blog.ChangePassByEmailDto;
import com.springboot.returndata.dto.blog.UserEamilLoginDto;
import com.springboot.returndata.dto.blog.UserEamilRegisterDto;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.springboot.returndata.vo.blog.BlogSortVo;
import com.springboot.returndata.vo.blog.BlogUserVo;
import com.springboot.util.common.MyDateUtil;
import com.springboot.util.constant.CommonContract;
import com.springboot.util.enums.RespErrorCode;
import com.springboot.util.mail.MyMailUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 博客用户 服务类
 * </p>
 *
 * @author zyj
 * @since 2023-05-04
 */
@Service
public class BlogUserService extends ServiceImpl<BlogUserDao, BlogUserEntity> {

    @Resource
    private MyMailUtil myMailUtil;

    @Resource
    private BlogRegisterTimeDao blogRegisterTimeDao;

    @Resource
    private BlogUserDao blogUserDao;

    @Value("${project.blog_jwt_token:1000}")
    private int blogTokenTime;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private BlogUserLoginJwtDao blogUserLoginJwtDao;

    @Resource
    private BlogCommentDao blogCommentDao;


    /**
     * 方法描述 忘记发送邮箱验证码
     * @since: 1.0
     * @param email
     * @return: void
     * @author: zyj
     * @date: 2023/5/17 16:28
     */
    public String sendEamilForgetCode(String email) throws Exception{
        //校验用户
        BlogUserEntity blogUserEntities = blogUserDao.selectByEamil(email);
        if(ObjectUtil.isEmpty(blogUserEntities)){
            throw new MySpringBootException(RespErrorCode.BLOG_EMAIL_ERROR.getValue(), RespErrorCode.BLOG_EMAIL_ERROR.getDescripe());
        }

        /**step1:生成验证码*/
        CodeGenerator mathGenerator = new RandomGenerator(4);
        String generate = mathGenerator.generate();

        /**step2:发送邮件*/
        String sendId = myMailUtil.sendEmailRegister(email, generate);

        /**step3:保存信息*/
        BlogRegisterTimeEntity blogRegisterTimeEntity = new BlogRegisterTimeEntity();
        blogRegisterTimeEntity.setRegisterEmail(email);
        blogRegisterTimeEntity.setRegisterCode(generate);
        blogRegisterTimeEntity.setSendId(sendId);
        //失效时间
        DateTime offset = DateUtil.offset(DateUtil.date(), DateField.MINUTE, 5);
        blogRegisterTimeEntity.setLoseTime(offset);
        blogRegisterTimeDao.insert(blogRegisterTimeEntity);

        return sendId;
    }

    /**
     * 方法描述 忘记密码 通过邮箱修改密码
     * @since: 1.0
     * @param userEamilRegisterDto
     * @return: void
     * @author: zyj
     * @date: 2023/5/18 13:23
     */
    public void changePassByEmail(ChangePassByEmailDto userEamilRegisterDto) throws Exception {
        /**1、校验用户、校验验证码*/
        //校验邮箱
//        BlogRegisterTimeEntity bRTime = blogRegisterTimeDao.selectByEmailAndSendId(userEamilRegisterDto.getUserEmail(), userEamilRegisterDto.getSendId());
//        if(bRTime.getLoseTime().before(DateUtil.date()) || !StrUtil.equals(bRTime.getSendId(), userEamilRegisterDto.getSendId()) ||
//                !StrUtil.equals(bRTime.getRegisterCode(), userEamilRegisterDto.getEmailCode())){
//            throw new MySpringBootException(RespErrorCode.VERI_CODE_NULL.getValue(), RespErrorCode.VERI_CODE_NULL.getDescripe());
//        }

        //校验用户
        BlogUserEntity blogUserEntities = blogUserDao.selectByEamil(userEamilRegisterDto.getUserEmail());
        if(ObjectUtil.isEmpty(blogUserEntities) ){
            throw new MySpringBootException(RespErrorCode.USER_NULL.getValue(), RespErrorCode.USER_NULL.getDescripe());
        }

        /**2、保存用户*/
        //保存密码
        String hashPwd = DigestUtil.bcrypt(userEamilRegisterDto.getPwd());
        blogUserEntities.setPasswd(hashPwd);

        blogUserDao.updateById(blogUserEntities);
    }

    /**
     * 方法描述 发送邮箱验证码
     * @since: 1.0
     * @param email
     * @return: void
     * @author: zyj
     * @date: 2023/5/17 16:28
     */
    public String sendEamilCode(String email) throws Exception{
        /**step1:生成验证码*/
        CodeGenerator mathGenerator = new RandomGenerator(4);
        String generate = mathGenerator.generate();

        /**step2:发送邮件*/
        String sendId = myMailUtil.sendEmailRegister(email, generate);

        /**step3:保存信息*/
        BlogRegisterTimeEntity blogRegisterTimeEntity = new BlogRegisterTimeEntity();
        blogRegisterTimeEntity.setRegisterEmail(email);
        blogRegisterTimeEntity.setRegisterCode(generate);
        blogRegisterTimeEntity.setSendId(sendId);
        //失效时间
        DateTime offset = DateUtil.offset(DateUtil.date(), DateField.MINUTE, 5);
        blogRegisterTimeEntity.setLoseTime(offset);
        blogRegisterTimeDao.insert(blogRegisterTimeEntity);

        return sendId;
    }


    /**
     * 方法描述 用户注册
     * @since: 1.0
     * @param userEamilRegisterDto
     * @return: void
     * @author: zyj
     * @date: 2023/5/18 13:23
     */
    public void userEamilRegister(UserEamilRegisterDto userEamilRegisterDto) throws Exception{
        /**1、校验用户、校验验证码*/
        //校验邮箱
        BlogRegisterTimeEntity bRTime = blogRegisterTimeDao.selectByEmailAndSendId(userEamilRegisterDto.getUserEmail(), userEamilRegisterDto.getSendId());
        if(bRTime.getLoseTime().before(DateUtil.date()) || !StrUtil.equals(bRTime.getSendId(), userEamilRegisterDto.getSendId()) ||
                !StrUtil.equals(bRTime.getRegisterCode(), userEamilRegisterDto.getEmailCode())){
            throw new MySpringBootException(RespErrorCode.VERI_CODE_NULL.getValue(), RespErrorCode.VERI_CODE_NULL.getDescripe());
        }

        //校验用户
        BlogUserEntity blogUserEntities = blogUserDao.selectByNameOrEamil(userEamilRegisterDto.getUserName(), userEamilRegisterDto.getUserEmail());
        if(!ObjectUtil.isEmpty(blogUserEntities) ){
            throw new MySpringBootException(RespErrorCode.BLOG_USER_HAS_ERROR.getValue(), RespErrorCode.BLOG_USER_HAS_ERROR.getDescripe());
        }

        /**2、保存用户*/
        BlogUserEntity blogUserEntity = BlogUserEntity.cover(userEamilRegisterDto);
        blogUserEntity.setUserHeader(CommonContract.registerHeader);

        //保存密码
        String hashPwd = DigestUtil.bcrypt(userEamilRegisterDto.getPwd());
        blogUserEntity.setPasswd(hashPwd);

        blogUserDao.insert(blogUserEntity);
    }


    /**
     * 方法描述 用户名邮箱登录
     * @since: 1.0
     * @param userEamilLogin
     * @return: String
     * @author: zyj
     * @date: 2023/5/23 11:03
     */
    public Map<String, String> userEamilLogin(UserEamilLoginDto userEamilLogin) throws Exception{
        String userEmail = userEamilLogin.getUserEmail();
        String passwd = userEamilLogin.getPasswd();
        /**1、查询用户信息*/
        BlogUserEntity blogUserEntity = blogUserDao.selectByNameOrEamil(userEmail, userEmail);
        if(ObjectUtil.isEmpty(blogUserEntity)){
            throw new MySpringBootException(RespErrorCode.BLOG_USER_HAS_NULL.getValue(), RespErrorCode.BLOG_USER_HAS_NULL.getDescripe());
        }

        /**2、校验密码*/
        String pass = blogUserEntity.getPasswd();
        boolean passCheck = DigestUtil.bcryptCheck(passwd, pass);
        if(!passCheck){
            throw new MySpringBootException(RespErrorCode.BLOG_USER_HAS_NULL.getValue(), RespErrorCode.BLOG_USER_HAS_NULL.getDescripe());
        }

        /**3.生成jwt*/
        Date date = new Date();
        JWTPayload jwtPayload = new JWTPayload();
        String [] userIds = new String[]{String.valueOf(blogUserEntity.getId())};
        jwtPayload.setAud(userIds);
        jwtPayload.setExp(MyDateUtil.getLocalTimeAfter(blogTokenTime));
        jwtPayload.setNbf(date);
        jwtPayload.setIat(date);
        jwtPayload.setJti(blogUserEntity.getUserEmail());
        String token = jwtUtil.jwtCreate(new JWTHeaderDto(), jwtPayload, blogUserEntity.getPasswd());

        /**4、保存有效期*/
        BlogUserLoginJwtEntity blogUserLoginJwtEntity = new BlogUserLoginJwtEntity();
        blogUserLoginJwtEntity.setJwt(token);
        blogUserLoginJwtEntity.setEndTime(MyDateUtil.getLocalTimeAfter(blogTokenTime));
        blogUserLoginJwtEntity.setUserId(blogUserEntity.getId());
        blogUserLoginJwtDao.insert(blogUserLoginJwtEntity);

        //返回数据
        Map<String, String> result = new HashMap<>();
        result.put("jwt", token);
        result.put("userName", blogUserEntity.getUserName());
        return result;
    }

    /**
     * 方法描述 退出登录
     * @since: 1.0
     * @param jwt
     * @return: void
     * @author: zyj
     * @date: 2023/5/24 13:33
     */
    public void logOut(String jwt){
        /**jwt获取用户id*/
        String userId = JWT.decode(jwt).getAudience().get(0);
        blogUserLoginJwtDao.deleteByUserId(userId);
    }


    /**
     * 方法描述 评论
     * @since: 1.0
     * @param blogCommentDto
     * @return: void
     * @author: zyj
     * @date: 2023/5/25 19:16
     */
    public void blogComment(BlogCommentDto blogCommentDto){

        /**保存评论*/
        BlogCommentEntity blogCommentEntity = new BlogCommentEntity();
        BeanUtils.copyProperties(blogCommentDto, blogCommentEntity);
        blogCommentEntity.setCommentTime(MyDateUtil.format(new Date(), MyDateUtil.dateFormatStr));

        blogCommentDao.insert(blogCommentEntity);
    }

    /**
     * 获取文章分类列表
     *
     * @param blogUserPageDto
     * @return
     */
    public Page<BlogUserVo> pageBlogUser(BlogUserPageDto blogUserPageDto) {
        Page<BlogUserVo> roleList = blogUserDao.pageBlogUser(blogUserPageDto.getPage(), blogUserPageDto);
        return roleList;
    }
}
